﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace Kimd.Communication
{
    public enum SoftElemType
    {
        //AM600
        ELEM_QX = 0,     //QX元件
        ELEM_MW = 1,     //MW元件
        ELEM_X = 2,		 //X元件(对应QX200~QX300)
        ELEM_Y = 3,		 //Y元件(对应QX300~QX400)

        //H3U
        REGI_H3U_Y = 0x20,       //Y元件的定义	
        REGI_H3U_X = 0x21,		//X元件的定义							
        REGI_H3U_S = 0x22,		//S元件的定义				
        REGI_H3U_M = 0x23,		//M元件的定义							
        REGI_H3U_TB = 0x24,		//T位元件的定义				
        REGI_H3U_TW = 0x25,		//T字元件的定义				
        REGI_H3U_CB = 0x26,		//C位元件的定义				
        REGI_H3U_CW = 0x27,		//C字元件的定义				
        REGI_H3U_DW = 0x28,		//D字元件的定义				
        REGI_H3U_CW2 = 0x29,	    //C双字元件的定义
        REGI_H3U_SM = 0x2a,		//SM
        REGI_H3U_SD = 0x2b,		//
        REGI_H3U_R = 0x2c,		//
        //H5u
        REGI_H5U_Y = 0x30,       //Y元件的定义	
        REGI_H5U_X = 0x31,		//X元件的定义							
        REGI_H5U_S = 0x32,		//S元件的定义				
        REGI_H5U_M = 0x33,		//M元件的定义	
        REGI_H5U_B = 0x34,       //B元件的定义
        REGI_H5U_D = 0x35,       //D字元件的定义
        REGI_H5U_R = 0x36,       //R字元件的定义

    }
    public class InovancePLCOperator : IPlc
    {
        #region 标准库
        //StandardModbusApi.dll
        //[DllImport("StandardModbusApi.dll", EntryPoint = "Init_ETH_String", CallingConvention = CallingConvention.Cdecl)]
        

        [DllImport("StandardModbusApi.dll", EntryPoint = "Init_ETH_String", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool Init_ETH_String(string sIpAddr, int nNetId = 0, int IpPort = 502);

        [DllImport("StandardModbusApi.dll", EntryPoint = "Exit_ETH", CallingConvention = CallingConvention.Cdecl)]
        public static extern bool Exit_ETH(int nNetId = 0);

        [DllImport("StandardModbusApi.dll", EntryPoint = "H5u_Write_Soft_Elem", CallingConvention = CallingConvention.Cdecl)]
        public static extern int H5u_Write_Soft_Elem(SoftElemType eType, int nStartAddr, int nCount, byte[] pValue, int nNetId = 0);

        [DllImport("StandardModbusApi.dll", EntryPoint = "H5u_Read_Soft_Elem", CallingConvention = CallingConvention.Cdecl)]
        public static extern int H5u_Read_Soft_Elem(SoftElemType eType, int nStartAddr, int nCount, byte[] pValue, int nNetId = 0);

        [DllImport("StandardModbusApi.dll", EntryPoint = "H5u_Read_Device_Block", CallingConvention = CallingConvention.Cdecl)]
        public static extern int H5u_Read_Device_Block(SoftElemType eType, int nStartAddr, int nCount, byte[] pValue, int nNetId = 0);

        [DllImport("StandardModbusApi.dll", EntryPoint = "H5u_Write_Device_Block", CallingConvention = CallingConvention.Cdecl)]
        public static extern int H5u_Write_Device_Block(SoftElemType eType, int nStartAddr, int nCount, byte[] pValue, int nNetId = 0);

        [DllImport("StandardModbusApi.dll", EntryPoint = "Am600_Write_Soft_Elem", CallingConvention = CallingConvention.Cdecl)]
        public static extern int Am600_Write_Soft_Elem(SoftElemType eType, int nStartAddr, int nCount, byte[] pValue, int nNetId = 0);

        [DllImport("StandardModbusApi.dll", EntryPoint = "Am600_Read_Soft_Elem", CallingConvention = CallingConvention.Cdecl)]
        public static extern int Am600_Read_Soft_Elem(SoftElemType eType, int nStartAddr, int nCount, byte[] pValue, int nNetId = 0);
        #endregion
        private byte _stationNo;
        public bool Connect(string ip, int port, byte StationNo)
        {
            bool result = true;
            try
            {
                int nIpPort = port;
                _stationNo = StationNo;
                result = Init_ETH_String(ip, _stationNo, nIpPort);
            }
            catch (Exception ex)
            {
                result = false;
            }
            return result;
        }

        public bool Close()
        {
            bool result;
            try
            {
                result = Exit_ETH(_stationNo);
            }
            catch (Exception ex)
            {
                result = false;
            }
            return result;
        }

        public bool Read(string series, RegisterType registerType, DataType dataType, int startAddress, int length, out List<string> values, out int errCode)
        {
            errCode = 0;
            //缓冲区。读取整型字元件则一个元件占两个byte，位元件则占一个byte。例如读取D元件500个，则缓冲区大小为1000以上
            int dataLength = 0;
            switch(dataType)
            {
                case DataType.Bool:
                    dataLength = 1;
                    break;
                case DataType.Short:
                    dataLength = 2;
                    break;
                case DataType.Int:
                    dataLength = 4;
                    break;
                case DataType.Float:
                    dataLength = 4;
                    break;
            }
            byte[] pBuf = new byte[dataLength * length];
            values = new List<string>();
            SoftElemType elemType = SoftElemType.ELEM_MW;
            switch(registerType)
            {
                case RegisterType.QX:
                    elemType = SoftElemType.ELEM_QX;
                    break;
                case RegisterType.M:
                    elemType = SoftElemType.REGI_H5U_M;
                    break;
                case RegisterType.MW:
                    elemType = SoftElemType.ELEM_MW;
                    break;
                case RegisterType.D:
                    elemType = SoftElemType.REGI_H5U_D;
                    break;
            }
            int nRet = 0;
            if (series == "AM")
            {
                nRet = Am600_Read_Soft_Elem(elemType, startAddress, pBuf.Length, pBuf, _stationNo);
            }
            else if (series == "H5U")
            {
                nRet = H5u_Read_Device_Block(elemType, startAddress, pBuf.Length, pBuf, _stationNo);
            }
            else
                return false;
            values = new List<string>();
            if (nRet == 1)
            {
                switch (dataType)
                {
                    case DataType.Bool:
                        for (int i = 0; i < length; i++)
                        {
                            string iTemp = pBuf[i].ToString();
                            values.Add(iTemp);
                        }
                        break;
                    case DataType.Short:
                        byte[] databuf = new byte[2] { 0, 0 };
                        for (int i = 0; i < length; i++)
                        {
                            databuf[0] = pBuf[i * 2];
                            databuf[1] = pBuf[i * 2 + 1];
                            string iTemp = BitConverter.ToInt16(databuf, 0).ToString();
                            values.Add(iTemp);
                        }
                        break;
                    case DataType.Int:
                        byte[] databuf2 = new byte[4] { 0, 0, 0, 0 };
                        for (int i = 0; i < length; i++)
                        {
                            databuf2[0] = pBuf[i * 4];
                            databuf2[1] = pBuf[i * 4 + 1];
                            databuf2[2] = pBuf[i * 4 + 2];
                            databuf2[3] = pBuf[i * 4 + 3];
                            string iTemp = BitConverter.ToInt32(databuf2, 0).ToString();
                            values.Add(iTemp);
                        }
                        break;
                    case DataType.Float:
                        byte[] databuf3 = new byte[4] { 0, 0, 0, 0 };
                        for (int i = 0; i < length; i++)
                        {
                            databuf3[0] = pBuf[i * 4];
                            databuf3[1] = pBuf[i * 4 + 1];
                            databuf3[2] = pBuf[i * 4 + 2];
                            databuf3[3] = pBuf[i * 4 + 3];
                            string fTemp = BitConverter.ToSingle(databuf3, 0).ToString("0.0000");
                            values.Add(fTemp);
                        }
                        break;
                }
            }
            else
                errCode = nRet;
            return nRet == 1;
        }

        public bool Write(string series, RegisterType registerType, DataType dataType, int startAddress, List<string> values, out int errCode)
        {
            errCode = 0;
            int dataLength = 0;
            switch (dataType)
            {
                case DataType.Bool:
                    dataLength = 1;
                    break;
                case DataType.Short:
                    dataLength = 2;
                    break;
                case DataType.Int:
                    dataLength = 4;
                    break;
                case DataType.Float:
                    dataLength = 4;
                    break;
            }
            byte[] pBuf = new byte[dataLength * values.Count];
            SoftElemType elemType = SoftElemType.REGI_H5U_Y;
            switch (registerType)
            {
                case RegisterType.QX:
                    elemType = SoftElemType.ELEM_QX;
                    break;
                case RegisterType.M:
                    elemType = SoftElemType.REGI_H5U_M;
                    break;
                case RegisterType.MW:
                    elemType = SoftElemType.ELEM_MW;
                    break;
                case RegisterType.D:
                    elemType = SoftElemType.REGI_H5U_D;
                    break;
            }
            for (int i = 0; i < values.Count; i++)
            {
                if (values[i] == string.Empty)
                {
                    break;
                }
                switch(dataType)
                {
                    case DataType.Bool:
                        pBuf[i] = Convert.ToByte(values[i]);
                        break;
                    case DataType.Short:
                        int sdata = Convert.ToInt16(values[i]);
                        byte[] sdataBuf = new byte[2] { 0, 0 };
                        sdataBuf = BitConverter.GetBytes(sdata);
                        pBuf[2 * i] = sdataBuf[0];
                        pBuf[2 * i + 1] = sdataBuf[1];
                        break;
                    case DataType.Int:
                        int idata = Convert.ToInt32(values[i]);
                        byte[] idataBuf = new byte[4] { 0, 0, 0, 0 };
                        idataBuf = BitConverter.GetBytes(idata);
                        pBuf[4 * i] = idataBuf[0];
                        pBuf[4 * i + 1] = idataBuf[1];
                        pBuf[4 * i + 2] = idataBuf[2];
                        pBuf[4 * i + 3] = idataBuf[3];
                        break;
                    case DataType.Float:
                        float fdata = Convert.ToSingle(values[i]);
                        byte[] dataBuf = new byte[4] { 0, 0, 0, 0 };
                        dataBuf = BitConverter.GetBytes(fdata);
                        pBuf[4 * i] = dataBuf[0];
                        pBuf[4 * i + 1] = dataBuf[1];
                        pBuf[4 * i + 2] = dataBuf[2];
                        pBuf[4 * i + 3] = dataBuf[3];
                        break;
                }
            }
            int nRet = 0;
            if (series == "AM")
                nRet = Am600_Write_Soft_Elem(elemType, startAddress, pBuf.Length, pBuf, _stationNo);
            else if(series == "H5U")
                nRet = H5u_Write_Device_Block(elemType, startAddress, pBuf.Length, pBuf, _stationNo);
            if (nRet != 1)
                errCode = nRet;
            return nRet == 1;
        }
    }
}
